package hu.mapro.rollerx.core;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Peripheral;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.Align;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;

public class RollerXGameScreen implements Screen {
	
	enum GameState {
		RUNNING,
		PAUSED,
		
	}
	
	public static final float VIEW_WIDTH = 30;
	
	private RollerWorld rollerWorld;
	private Box2DDebugRenderer debugRenderer;

	OrthographicCamera camera;
	float rotation = 0f;
	
//	PolygonSprite poly;
//	PolygonSpriteBatch polyBatch;

	
	GameState state = GameState.PAUSED;

	public Runnable controlCallback = null;
	
	public boolean useAccelerometer = false;

	private BitmapFont font;
	SpriteBatch batch;
	
//	int graphicsWidth;
//	int graphicsHeight;

	private Stage stage;

	private InputMultiplexer inputs;

	private BitmapFont titleFont;

	private Table menuTable;

	private TextButton exitButton;

	private TextButton restartButton;

	private TextButton resumeButton;

	private Label title;

	private float fontHeight;

	private OrthographicCamera hudCamera;
	private ShapeRenderer hudRenderer;

//	private EarClippingTriangulator triangulator;

//	private TextureRegion textureRegion;
	
	private float hudRadius = 100;
	
	public RollerXGameScreen () {
		
		// physics world
		
		camera = new OrthographicCamera();
		
		hudCamera = new OrthographicCamera();
		
		sizeCamera();
		
		
		debugRenderer = new Box2DDebugRenderer() {
			@Override
			protected void renderBody(Body body) {
				if (body.getType() != BodyType.StaticBody) {
					super.renderBody(body);
				}
			}
		};
		debugRenderer.setDrawJoints(false);
		
//		triangulator = new EarClippingTriangulator();
//		
//		Pixmap pixmap = new Pixmap(1, 1, Format.RGB888);
//		pixmap.setColor(Color.GRAY);
//		pixmap.drawPixel(0, 0);
//		Texture texture = new Texture(pixmap);
//		
////		Texture texture = new Texture(Gdx.files.internal("libgdx-logo.png"));
////		texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
//		
//		textureRegion = new TextureRegion(texture);
		
		
		// pause
		
		titleFont = new BitmapFont(Gdx.files.internal("rollerx.fnt"), Gdx.files.internal("rollerx.png"), false);
		font = new BitmapFont(Gdx.files.internal("rollerx.fnt"), Gdx.files.internal("rollerx.png"), false);
		fontHeight = font.getLineHeight();
		batch = new SpriteBatch();
		
		
		float onePer160InchInPixels = Gdx.graphics.getDensity();
		float zeroPoint3InchInPixels = 0.4f * onePer160InchInPixels / (1f/160f);
		
		//float targetHeight = Math.min(maxHeightPixels, zeroPoint3InchInPixels);
		float targetHeight = zeroPoint3InchInPixels;
		//float targetHeight = maxHeightPixels;
		
		titleFont.setScale(targetHeight/fontHeight*1.5f);
		font.setScale(targetHeight/fontHeight);
		
		
		// control
		
		inputs = new InputMultiplexer();
		Gdx.input.setInputProcessor(inputs);
		
		inputs.addProcessor(new InputAdapter() {
			@Override
			public boolean mouseMoved(int screenX, int screenY) {
				
				Vector2 mouseVector = new Vector2(screenX - Gdx.graphics.getWidth()/2, screenY - Gdx.graphics.getHeight()/2);
				
				rotation = 90-mouseVector.angle();
						
						//(((float)screenX / Gdx.graphics.getWidth())-0.5f)*360f;
				
				hudRadius = mouseVector.len();
				
				sizeCamera();
				
				rollerWorld.setGravityAngle(rotation);
				
				return super.mouseMoved(screenX, screenY);
			}
		});
		
		useAccelerometer = Gdx.input.isPeripheralAvailable(Peripheral.Accelerometer);
		
		if (!useAccelerometer) {
			hudRenderer = new ShapeRenderer();
			hudRenderer.setColor(new Color(1, 0, 0, 0.5f));
		}
		
		// menu
		
		stage = new Stage();
		
		menuTable = new Table();
        menuTable.setFillParent(true);
        stage.addActor(menuTable);

        LabelStyle titleStyle = new LabelStyle();
        titleStyle.font = titleFont;
        titleStyle.fontColor = Color.BLUE;
        TextButtonStyle buttonStyle = new TextButtonStyle();
        buttonStyle.font = font;
        buttonStyle.fontColor = Color.WHITE;
        buttonStyle.overFontColor = Color.GREEN;

        title = new Label("Game Paused", titleStyle);
        title.setAlignment(Align.center);
        menuTable.add(title);
        menuTable.row();
        
        
        
        resumeButton = new TextButton("Resume", buttonStyle);
        menuTable.add(resumeButton);
        menuTable.row();

        restartButton = new TextButton("Restart", buttonStyle);
        menuTable.add(restartButton);        
        menuTable.row();
		
        exitButton = new TextButton("Exit", buttonStyle);
        menuTable.add(exitButton);        
        menuTable.row();

        resumeButton.addListener(new ClickListener() {
        	@Override
        	public void clicked(InputEvent event, float x, float y) {
        		super.clicked(event, x, y);
        		unpause();
        	}
        });
        
        restartButton.addListener(new ClickListener() {
        	@Override
        	public void clicked(InputEvent event, float x, float y) {
        		super.clicked(event, x, y);
        		rollerWorld.dispose();
        		start();
        		unpause();
        	}
        });
        
        exitButton.addListener(new ClickListener() {
        	@Override
        	public void clicked(InputEvent event, float x, float y) {
        		super.clicked(event, x, y);
        		Gdx.app.exit();
        	}
        });
        
        
        // size
        
        start();
		pause();
	}

	@Override
	public void resize (int width, int height) {
//		graphicsWidth = width;
//		graphicsHeight = height;

		stage.setViewport(width, height, true);
		
//		float maxHeightPixels = height/6f;
//		float onePer160InchInPixels = Gdx.graphics.getDensity();
//		float zeroPoint3InchInPixels = 0.4f * onePer160InchInPixels / (1f/160f);
//		
//		//float targetHeight = Math.min(maxHeightPixels, zeroPoint3InchInPixels);
//		//float targetHeight = zeroPoint3InchInPixels;
//		float targetHeight = maxHeightPixels;
//		
//		titleFont.setScale(targetHeight/fontHeight*1.5f);
//		font.setScale(targetHeight/fontHeight);

//		title.invalidate();
//        resumeButton.invalidate();
//        restartButton.invalidate();
//        exitButton.invalidate();
//        title.invalidateHierarchy();
//        resumeButton.invalidateHierarchy();
//        restartButton.invalidateHierarchy();
//        exitButton.invalidateHierarchy();
		
//		menuTable.invalidate();
//		stage.setViewport(width, height, false);
//		menuTable.invalidate();
//		stage.setViewport(width, height, false);
//		menuTable.invalidate();
//		stage.setViewport(width, height, false);
		
		hudCamera.setToOrtho(false);
		hudCamera.translate(-width/2, -height/2);
		hudCamera.update();
		
		sizeCamera();
	}

	@Override
	public void render (float deltaTime) {
		control();
		
		Gdx.gl.glClearColor(0, 0, 0, 0);
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		
		switch (state) {
		case PAUSED:
			renderPaused(deltaTime);
			break;
		case RUNNING:
			renderRunning(deltaTime);
			break;
		}
		
	}

	private void control() {
		if (controlCallback!=null) {
			controlCallback.run();
		}
		
		if (useAccelerometer) {
			float accelX = Gdx.input.getAccelerometerX();
		    float accelY = Gdx.input.getAccelerometerY();

		    if (accelY!=0 || accelX!=0) {
		    	float rot = MathUtils.atan2(-accelY, accelX);

		    	rollerWorld.setGravityAngle(rot * MathUtils.radiansToDegrees);
		    }
		}
	}
	
	
	private void renderPaused(float deltaTime) {
		drawRunning();
		
        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
		
//		if (Gdx.input.justTouched()) {
//			unpause();
//		}
	}

	public void renderRunning (float deltaTime) {
		drawRunning();
		updateRunning(deltaTime);
	}

	private void updateRunning(float deltaTime) {
		
		if (Gdx.input.justTouched()) {
			pause();
		}
		
		rollerWorld.step(deltaTime);
	}

	private void drawRunning() {
		
		Vector2 carCenter = rollerWorld.getView();
		camera.position.set(carCenter.x, carCenter.y, 0f);
		camera.update();
		
//		polyBatch.setProjectionMatrix(camera.combined);
//		polyBatch.begin();
//		poly.draw(polyBatch);
//		polyBatch.end();

		rollerWorld.ground.render(camera);
		
		debugRenderer.render(rollerWorld.world, camera.combined);
		
		if (!useAccelerometer) {
			Gdx.gl.glEnable(GL10.GL_BLEND);
			Gdx.gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
			
			hudRenderer.setProjectionMatrix(hudCamera.combined);
			hudRenderer.begin(ShapeType.Line);
			hudRenderer.circle(0, 0, hudRadius);
			hudRenderer.end();
			
			Gdx.gl.glDisable(GL10.GL_BLEND);
		}
	}

	@Override
	public void pause () {
		state = GameState.PAUSED;
		inputs.addProcessor(stage);
	}

	void unpause() {
		state = GameState.RUNNING;
		inputs.removeProcessor(stage);
	}
	
	@Override
	public void resume () {
	}

	@Override
	public void dispose () {
		stage.dispose();
	}
	
	
	public void sizeCamera() {
		camera.viewportWidth = Gdx.graphics.getWidth();
		camera.viewportHeight = Gdx.graphics.getHeight();
		camera.up.set(0, 1, 0);
		camera.direction.set(0, 0, 1);
		camera.zoom = VIEW_WIDTH / camera.viewportWidth;
		//camera.position.set(0, getMiddlePointHeight(), 0);
		camera.rotate(rotation);
		camera.update();
	}

	@Override
	public void show() {
	}

	@Override
	public void hide() {
	}

	void start() {
		rollerWorld = new RollerWorld(new Car2(), new Ground6(), new Cargo1());

//		PolygonRegion polyReg = new PolygonRegion(
//				textureRegion,
//			    rollerWorld.terrainVertices,
//			    triangulator.computeTriangles(rollerWorld.terrainVertices).toArray()
//		);
//		textureMap(polyReg, 1/50f);
//		poly = new PolygonSprite(polyReg);
//		polyBatch = new PolygonSpriteBatch(rollerWorld.terrainVertices.length/2);

		rollerWorld.setGravityAngle(rotation);
	
		resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		
	}
}
